package io.itit.ecp.admin.provide.action.controller;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.provide.action.req.CarbonEmissionPlanQueryReq;
import io.itit.ecp.admin.provide.action.req.CarbonEmissionPlanReq;
import io.itit.ecp.admin.provide.action.resp.CarbonEmissionPlanDetailResp;
import io.itit.ecp.admin.provide.action.resp.CarbonEmissionPlanResp;
import io.itit.ecp.admin.provide.renderer.CarbonEmissionPlanRenderer;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.ICarbonEmissionPlanDataService;
import io.itit.ecp.admin.server.service.ICarbonEmissionPlanDetailService;
import io.itit.ecp.admin.server.service.ICarbonEmissionPlanService;
import io.itit.grass.common.exception.GrassException;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.*;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.common.utils.Y666Utils;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.parse.ExcelParseManage;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：碳排放规划配置控制类
 * @Date：Create by 2024-01-11 16:45:38
 */
@Api(tags = "碳排放规划配置")
@RestController
@RequestMapping("/ecp-admin/carbonEmissionPlan")
public class CarbonEmissionPlanController {

    @Resource
    private ICarbonEmissionPlanService carbonEmissionPlanService;
    @Resource
    private ICarbonEmissionPlanDetailService carbonEmissionPlanDetailService;
    @Resource
    private ICarbonEmissionPlanDataService carbonEmissionPlanDataService;

    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:search")
    public ResultResp<IPage<CarbonEmissionPlanResp>> queryPage(@RequestBody @Validated(IQueryPage.class) CarbonEmissionPlanQueryReq req) {
        Page<CarbonEmissionPlanResp> page = buildQW(req).joinPage(PageUtils.getPage(req, CarbonEmissionPlanResp.class), CarbonEmissionPlanResp.class);
        buildDetail(page.getRecords());
        return ResultResp.success(page);
    }

    @ApiOperation("详情")
    @PostMapping("detail")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:search")
    public ResultResp<CarbonEmissionPlanResp> detail(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        CarbonEmissionPlanResp planResp = group()
                .eq(CarbonEmissionPlanEntity::getId, req.getId())
                .joinGetOne(CarbonEmissionPlanResp.class);
        buildDetail(Collections.singletonList(planResp));
        return ResultResp.success(planResp);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) CarbonEmissionPlanReq req) {
        GrassException.throwEx(CollectionUtils.isEmpty(req.getPlanDetailList()), "楼层规划碳排信息不能为空！");
        GrassException.throwEx(checkDate(req) > 0, "当前生效时间范围" + DateUtil.format(req.getEffectiveTimeStart(), DatePattern.NORM_DATE_PATTERN) + "/" + DateUtil.format(req.getEffectiveTimeEnd(), DatePattern.NORM_DATE_PATTERN) + "已存在重复设置！");
        List<CarbonEmissionPlanDetailEntity> planDetailList = req.getPlanDetailList().stream().map(x -> ConvertUtils.convertIgnoreId(x, CarbonEmissionPlanDetailEntity.class)).collect(Collectors.toList());
        return ResultResp.success(carbonEmissionPlanService.save(ConvertUtils.convertIgnoreId(req, CarbonEmissionPlanEntity.class), planDetailList));
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) CarbonEmissionPlanReq req) {
        GrassException.throwEx(CollectionUtils.isEmpty(req.getPlanDetailList()), "楼层规划碳排信息不能为空！");
        GrassException.throwEx(checkDate(req) > 0, "当前生效时间范围" + DateUtil.format(req.getEffectiveTimeStart(), DatePattern.NORM_DATE_PATTERN) + "/" + DateUtil.format(req.getEffectiveTimeEnd(), DatePattern.NORM_DATE_PATTERN) + "已存在重复设置！");
        List<CarbonEmissionPlanDetailEntity> planDetailList = req.getPlanDetailList().stream().map(x -> ConvertUtils.copy(x, CarbonEmissionPlanDetailEntity.class)).collect(Collectors.toList());
        return ResultResp.success(carbonEmissionPlanService.save(ConvertUtils.copy(req, CarbonEmissionPlanEntity.class), planDetailList));
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        boolean bool = carbonEmissionPlanService.removeById(req.getId());
        carbonEmissionPlanDetailService.remove(new LambdaQueryWrapper<CarbonEmissionPlanDetailEntity>().eq(CarbonEmissionPlanDetailEntity::getCarbonEmissionPlanId, req.getId()));
        deletePlanData(Collections.singletonList(req.getId()));
        return ResultResp.success(bool);
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        boolean bool = carbonEmissionPlanService.removeBatchByIds(req.getIds(), 1000);
        carbonEmissionPlanDetailService.remove(new LambdaQueryWrapper<CarbonEmissionPlanDetailEntity>().in(CarbonEmissionPlanDetailEntity::getCarbonEmissionPlanId, req.getIds()));
        deletePlanData(req.getIds());
        return ResultResp.success(bool);
    }

    @ApiOperation("导入")
    @PostMapping("upload")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:upload")
    public ResultResp<Integer> upload(@Validated(IUpload.class) CarbonEmissionPlanQueryReq req, @RequestParam("file") MultipartFile file, Boolean ignoreError) {
        CarbonEmissionPlanRenderer.threadLocal.set(req);
        return ResultResp.success(ExcelParseManage.i().process(CarbonEmissionPlanRenderer.ENTITY_NAME, file, ignoreError));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:carbonEmissionPlan:export")
    public void export(@RequestBody @Validated(IExport.class) CarbonEmissionPlanQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("CarbonEmissionPlanExport", JsonUtil.toJson(carbonEmissionPlanService.list(buildQW(req))), response);
    }

    @ApiOperation("校验日期是否存在交集")
    @PostMapping("checkDateIntersection")
    public ResultResp<Long> checkDateIntersection(@RequestBody @Validated({IRequired.class}) CarbonEmissionPlanReq req) {
        return ResultResp.success(checkDate(req));
    }

    /**
     * 检核日期是否存在交集
     *
     * @param req
     * @return
     */
    private Long checkDate(CarbonEmissionPlanReq req) {
        return carbonEmissionPlanService.lambdaQuery()
                .ne(StringUtils.isNotEmpty(req.getId()), CarbonEmissionPlanEntity::getId, req.getId())
                .eq(CarbonEmissionPlanEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(CarbonEmissionPlanEntity::getSceneEdificeId, req.getSceneEdificeId())
                .ge(CarbonEmissionPlanEntity::getEffectiveTimeEnd, req.getEffectiveTimeStart())
                .le(CarbonEmissionPlanEntity::getEffectiveTimeStart, req.getEffectiveTimeEnd()).count();
    }

    /**
     * build子表
     *
     * @param recordList
     */
    private void buildDetail(List<CarbonEmissionPlanResp> recordList) {
        for (CarbonEmissionPlanResp record : recordList) {
            List<CarbonEmissionPlanDetailResp> planDetailList = getPlanDetailList(record.getId(), record.getSceneProjectId(), record.getSceneEdificeId());
            BigDecimal carbonEmission = planDetailList.stream().map(x -> Y666Utils.add(Y666Utils.add(x.getElectric(), x.getWater()), x.getCold())).reduce(BigDecimal.ZERO, BigDecimal::add);
            record.setCarbonEmission(carbonEmission);
            record.setPlanDetailList(planDetailList);
        }
    }

    /**
     * 组装查询条件
     *
     * @param req
     * @return
     */
    private JoinLambdaWrapper<CarbonEmissionPlanEntity> buildQW(CarbonEmissionPlanQueryReq req) {
        return group()
                .eq(StringUtils.isNotEmpty(req.getSceneProjectId()), CarbonEmissionPlanEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.isNotEmpty(req.getSceneEdificeId()), CarbonEmissionPlanEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(req.getEffectiveTimeStart() != null, CarbonEmissionPlanEntity::getEffectiveTimeStart, req.getEffectiveTimeStart())
                .eq(req.getEffectiveTimeEnd() != null, CarbonEmissionPlanEntity::getEffectiveTimeEnd, req.getEffectiveTimeEnd())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), CarbonEmissionPlanEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), CarbonEmissionPlanEntity::getId, req.getIds())
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req))
                .orderByDesc(StringUtils.isEmpty(req.getSortColumn()), CarbonEmissionPlanEntity::getCreateTm);
    }

    private static List<CarbonEmissionPlanDetailResp> getPlanDetailList(String carbonEmissionId, String sceneProjectId, String sceneEdificeId) {
        return Joins.of(CarbonEmissionPlanDetailEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, CarbonEmissionPlanDetailEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getId, CarbonEmissionPlanDetailEntity::getSceneEdificeId)
                .select(SceneEdificeEntity::getEdificeName)
                .end()
                .eq(CarbonEmissionPlanDetailEntity::getCarbonEmissionPlanId, carbonEmissionId)
                .eq(CarbonEmissionPlanDetailEntity::getSceneProjectId, sceneProjectId)
                .eq(CarbonEmissionPlanDetailEntity::getSceneEdificeId, sceneEdificeId)
                .orderByDesc(CarbonEmissionPlanDetailEntity::getCreateTm).joinList(CarbonEmissionPlanDetailResp.class);
    }

    private JoinLambdaWrapper<CarbonEmissionPlanEntity> group() {
        return Joins.of(CarbonEmissionPlanEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, CarbonEmissionPlanEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getId, CarbonEmissionPlanEntity::getSceneEdificeId)
                .select(SceneEdificeEntity::getEdificeName)
                .end();
    }

    private void deletePlanData(List<String> id) {
        List<CarbonEmissionPlanEntity> planList = carbonEmissionPlanService.lambdaQuery().in(CarbonEmissionPlanEntity::getId, id).list();
        for (CarbonEmissionPlanEntity planEntity : planList) {
            carbonEmissionPlanDataService.delete(planEntity);
        }
    }
}